from decimal import Decimal
import re
from sqlalchemy import null, true,false
# 双模型校验数据；

def convert_to_chinese_amount(amount_str):
    """
    将金额转换为中文大写表示
    
    参数:
        amount_str: 金额字符串，如 "5727.79"
    
    返回:
        chinese_amount: 中文大写金额，如 "伍仟柒佰贰拾柒圆柒角玖分"
    """
    # 数字到中文大写的映射
    digit_map = {
        '0': '零', '1': '壹', '2': '贰', '3': '叁', '4': '肆',
        '5': '伍', '6': '陆', '7': '柒', '8': '捌', '9': '玖'
    }
    
    # 单位映射
    unit_map = {
        0: '分', 1: '角', 2: '圆',
        3: '拾', 4: '佰', 5: '仟', 6: '万',
        7: '拾', 8: '佰', 9: '仟', 10: '亿'
    }
    
    # 确保金额有两位小数
    try:
        amount = Decimal(amount_str).quantize(Decimal('0.01'))
        amount_str = str(amount)
    except:
        return "无法转换的金额"
    
    # 分离整数部分和小数部分
    if '.' in amount_str:
        int_part, decimal_part = amount_str.split('.')
        # 确保小数部分有两位
        if len(decimal_part) == 1:
            decimal_part += '0'
    else:
        int_part = amount_str
        decimal_part = '00'
    
    # 转换整数部分
    int_chinese = ''
    int_len = len(int_part)
    for i, digit in enumerate(int_part):
        position = int_len - i
        if digit != '0':
            int_chinese += digit_map[digit] + unit_map[position + 1]
        else:
            # 处理零的特殊情况
            if i > 0 and int_part[i-1] != '0':  # 避免连续零重复显示
                int_chinese += '零'
    
    # 转换小数部分
    decimal_chinese = ''
    if decimal_part[0] != '0':
        decimal_chinese += digit_map[decimal_part[0]] + '角'
    if decimal_part[1] != '0':
        decimal_chinese += digit_map[decimal_part[1]] + '分'
    
    # 组合整数和小数部分
    if int_chinese:
        result = int_chinese
        if not decimal_chinese:
            result += '整'
    else:
        result = '零圆'
    
    if decimal_chinese:
        result += decimal_chinese
    
    return result

def validate_and_correct_invoice_dict(invoice_data:dict)->tuple:
    """
    原理-基准：
    【（1）各字段和为第1基准；
    （2）totalAmount第2基准：各字段首先与totalAmount进行验证；
    （3）totalSmall-totalTax第3基准：如果totalAmount与各字段计算的值不一致;则与totalSmall-totalTax进行验证，
    如果totalSmall-totalTax与totalAmount的值一致，则将totalSmall-totalTax的值赋给totalAmount。】
    
    验证并修正发票处理思路：
    [
        1）数据预处理
        首先复制输入的发票数据，以避免修改原始数据
        将字符串形式的列表转换为真正的Python列表，方便后续处理
        确保所有列表字段存在，如果不存在则创建空列表
        确保所有列表字段的元素个数相同
        2）totalPrice验证与修正（需求1）
        计算totalPrice的总和，与totalAmount进行比较
        如果不相等，分别尝试number、unitPrice和taxAmount的总和是否等于totalAmount
        如果某个字段的总和等于totalAmount，则将该字段的值赋给totalPrice
        如果没有任何字段的总和等于totalAmount，则尝试与totalSmall-totalTax进行匹配，如果匹配成功则更新totalAmount的值
        3）taxAmount验证与修正（需求2）
        对每个项目，根据totalPrice和taxRate计算正确的taxAmount值
        将计算得到的值赋给taxAmount
        4）unit验证（需求3）
        检查每个unit值是否包含汉字
        如果不包含汉字，则将其置空
        5）unitPrice和number验证（需求4）
        检查unitPrice乘以number是否等于totalPrice
        如果不相等，则将unitPrice和number置空
        如果number为空，将unitPrice也置为空
        如果unitPrice完全等于totalPrice，且number全为1，且unit为空，则将unitPrice和number均置空
        6）数据后处理
        最后将所有列表字段转回字符串格式，保持与原始数据格式一致
        7）如果totalAmountAndTotalSmallVerify为true，则将totalSmall转为大写赋值给totalBig
    ]
    参数:
        invoice_data: 包含发票信息的字典
    
    返回:
        元组 (修正后的发票数据字典, 修改记录字典, 是否满足基准, 分项验证结果)
        修改记录字典格式: {"key": ["value1-修改前", "value2-修改后"]}，记录从输入到返回值的变化
        meetVerifyBaseline：是否满足基准: 如果各字段和=totalAmount或各字段和=totalSmall-totalTax，则meetVerifyBaseline=true,否则为false
        item_verify_result: 分项验证结果，包含以下键值对：
            - totalPriceAndTotalAmountVerify: 各字段和是否等于totalAmount
            - taxAmountAndTotalTaxVerify: taxAmount总和是否等于totalTax
            - totalAmountAndTotalSmallVerify: totalAmount+totalTax是否等于totalSmall
    """
    # 复制一份数据以便操作
    invoice = invoice_data.copy()
    
    # 创建修改记录字典
    modifications = {}
    
    # 创建满足基准标志
    meetVerifyBaseline = False
    
    # 创建分项验证结果字典
    item_verify_result = {
        "totalPriceAndTotalAmountVerify": False,
        "taxAmountAndTotalTaxVerify": False,
        "totalAmountAndTotalSmallVerify": False
    }
    
    # 定义需要处理的列表字段
    list_fields = ['tradeName', 'model', 'unit', 'number', 'unitPrice', 'totalPrice', 'taxRate', 'taxAmount']
    
    # 确保所有列表字段存在，如果不存在则添加空值
    for field in list_fields:
        if field not in invoice:
            invoice[field] = "[]"
    
    # 将字符串格式的列表转换为真正的Python列表
    for field in list_fields:
        if isinstance(invoice[field], str) and invoice[field].startswith('[') and invoice[field].endswith(']'):
            # 移除字符串中的引号和括号，然后分割
            cleaned = invoice[field].replace("'", "").replace("[", "").replace("]", "")
            if cleaned:
                invoice[field] = cleaned.split(', ')
            else:
                invoice[field] = []
        elif not isinstance(invoice[field], list):
            invoice[field] = []
    
    # 找出所有非空列表中的最大长度，用于统一长度
    max_length = 0
    for field in list_fields:
        if len(invoice[field]) > max_length:
            max_length = len(invoice[field])
    
    # 如果所有列表都为空，设置默认长度为1
    if max_length == 0:
        max_length = 1
    
    # 统一所有列表的长度
    for field in list_fields:
        # 如果列表为空，添加一个空元素
        if len(invoice[field]) == 0:
            invoice[field] = [""] * max_length
        # 如果列表长度不等于最大长度，补充空元素
        elif len(invoice[field]) < max_length:
            invoice[field].extend([""] * (max_length - len(invoice[field])))
    
    # 检查是否存在totalAmount，如果不存在，无法进行后续验证
    if 'totalAmount' not in invoice or not invoice['totalAmount']:
        invoice['totalAmount'] = "0"
    
    # 检查是否存在totalPrice，如果不存在或为空，使用unitPrice作为初始值
    if 'totalPrice' not in invoice or len(invoice['totalPrice']) == 0 or all(not price for price in invoice['totalPrice']):
        invoice['totalPrice'] = invoice['unitPrice'].copy()
    
    # (1) 验证totalPrice的总和是否等于totalAmount
    found_match = False
    try:
        total_amount = Decimal(invoice['totalAmount'])
        total_price_sum = sum(Decimal(price) for price in invoice['totalPrice'] if price)
        
        # 如果totalPrice总和不等于totalAmount，尝试其他字段
        if total_price_sum != total_amount:
            # 尝试number求和
            try:
                number_sum = sum(Decimal(num) for num in invoice['number'] if num)
                if number_sum == total_amount:
                    invoice['totalPrice'] = invoice['number'].copy()
                    found_match = True
            except:
                pass
            
            # 尝试unitPrice求和
            if not found_match:
                try:
                    unit_price_sum = sum(Decimal(price) for price in invoice['unitPrice'] if price)
                    if unit_price_sum == total_amount:
                        invoice['totalPrice'] = invoice['unitPrice'].copy()
                        found_match = True
                except:
                    pass
            
            # 尝试taxAmount求和
            if not found_match:
                try:
                    tax_amount_sum = sum(Decimal(tax) for tax in invoice['taxAmount'] if tax)
                    if tax_amount_sum == total_amount:
                        invoice['totalPrice'] = invoice['taxAmount'].copy()
                        found_match = True
                except:
                    pass
            
            # 如果没有找到匹配项，尝试与totalSmall-totalTax进行匹配
            if not found_match and 'totalSmall' in invoice and invoice['totalSmall'] and 'totalTax' in invoice and invoice['totalTax']:
                try:
                    total_small = Decimal(invoice['totalSmall'])
                    total_tax = Decimal(invoice['totalTax'])
                    calculated_total_amount = (total_small - total_tax).quantize(Decimal('0.01'))
                    
                    # 检查totalPrice的总和是否等于totalSmall-totalTax
                    if abs(total_price_sum - calculated_total_amount) < Decimal('0.1'):
                        # 更新totalAmount为正确的值
                        invoice['totalAmount'] = str(calculated_total_amount)
                        found_match = True
                except:
                    pass
    except Exception as e:
        pass
    
    # (2) 验证taxAmount是否等于totalPrice*taxRate
    for i in range(len(invoice['totalPrice'])):
        try:
            if invoice['totalPrice'][i] and invoice['taxRate'][i]:
                price = Decimal(invoice['totalPrice'][i])
                # 将百分比转换为小数
                rate_str = invoice['taxRate'][i].replace('%', '')
                rate = Decimal(rate_str) / 100
                
                # 计算税额
                calculated_tax = (price * rate).quantize(Decimal('0.01'))
                
                # 更新taxAmount
                if i < len(invoice['taxAmount']) and invoice['taxAmount'][i] != str(calculated_tax):
                    invoice['taxAmount'][i] = str(calculated_tax)
        except Exception as e:
            pass
    
    # (3) 验证单位unit，如果不是汉字，则置空
    for i in range(len(invoice['unit'])):
        try:
            # 检查是否包含汉字
            if not any('\u4e00' <= char <= '\u9fff' for char in invoice['unit'][i]) and invoice['unit'][i]:
                invoice['unit'][i] = ""
        except Exception as e:
            pass
    
    # 检查unitPrice是否完全等于totalPrice，且number全为1，且unit为空
    all_unit_empty = all(not unit for unit in invoice['unit'])
    all_number_one = all(num == "1" for num in invoice['number'] if num)
    unit_price_equals_total_price = all(
        (not up or not tp) or (Decimal(up) == Decimal(tp))
        for up, tp in zip(invoice['unitPrice'], invoice['totalPrice'])
        if up and tp
    )
    
    if all_unit_empty and all_number_one and unit_price_equals_total_price:
        # 将unitPrice和number均置空
        invoice['unitPrice'] = [""] * len(invoice['unitPrice'])
        invoice['number'] = [""] * len(invoice['number'])
    else:
        # (4) 验证单价unitPrice和数量number是否匹配totalPrice
        for i in range(len(invoice['totalPrice'])):
            try:
                # 如果number为空，将unitPrice也置为空
                if not invoice['number'][i]:
                    if invoice['unitPrice'][i]:  # 只有当unitPrice不为空时才算修改
                        invoice['unitPrice'][i] = ""
                # 如果unitPrice和number都有值，检查乘积是否等于totalPrice
                elif invoice['unitPrice'][i] and invoice['number'][i] and invoice['totalPrice'][i]:
                    unit_price = Decimal(invoice['unitPrice'][i])
                    number = Decimal(invoice['number'][i])
                    total_price = Decimal(invoice['totalPrice'][i])
                    
                    # 如果unitPrice*number不等于totalPrice，则置空
                    calculated_total = (unit_price * number).quantize(Decimal('0.01'))
                    if calculated_total != total_price:
                        invoice['unitPrice'][i] = ""
                        invoice['number'][i] = ""
            except Exception as e:
                pass
    
    # 将列表转回字符串格式
    for field in list_fields:
        if isinstance(invoice[field], list):
            invoice[field] = str(invoice[field])
    
    # 比较输入和输出，记录有变化的字段
    for field in invoice:
        if field in invoice_data:
            if invoice[field] != invoice_data[field]:
                modifications[field] = [invoice_data[field], invoice[field]]
        else:
            # 新增字段
            modifications[field] = [None, invoice[field]]
    
    # 在所有修改完成后进行分项验证
    try:
        # 将修改后的列表字段转换回Python列表以进行验证
        invoice_lists = {}
        for field in list_fields:
            if isinstance(invoice[field], str) and invoice[field].startswith('[') and invoice[field].endswith(']'):
                cleaned = invoice[field].replace("'", "").replace("[", "").replace("]", "")
                if cleaned:
                    invoice_lists[field] = cleaned.split(', ')
                else:
                    invoice_lists[field] = []
            else:
                invoice_lists[field] = []
        
        # 验证totalPrice与totalAmount的关系
        total_amount = Decimal(invoice['totalAmount']).quantize(Decimal('0.01'))
        total_price_sum = sum(Decimal(price) for price in invoice_lists['totalPrice'] if price).quantize(Decimal('0.01'))
        
        if total_price_sum == total_amount:
            meetVerifyBaseline = True
            item_verify_result["totalPriceAndTotalAmountVerify"] = True
        
        # 验证taxAmount与totalTax的关系
        if 'totalTax' in invoice and invoice['totalTax']:
            total_tax = Decimal(invoice['totalTax']).quantize(Decimal('0.01'))
            tax_amount_sum = sum(Decimal(tax) for tax in invoice_lists['taxAmount'] if tax).quantize(Decimal('0.01'))
            
            if tax_amount_sum == total_tax:
                item_verify_result["taxAmountAndTotalTaxVerify"] = True
        
        # 验证totalAmount+totalTax与totalSmall的关系
        if 'totalSmall' in invoice and invoice['totalSmall'] and 'totalTax' in invoice and invoice['totalTax']:
            total_small = Decimal(invoice['totalSmall']).quantize(Decimal('0.01'))
            total_tax = Decimal(invoice['totalTax']).quantize(Decimal('0.01'))
            
            # 检查totalAmount+totalTax是否等于totalSmall
            if (total_amount + total_tax) == total_small:
                item_verify_result["totalAmountAndTotalSmallVerify"] = True
                
                # 如果totalAmountAndTotalSmallVerify为true，将totalSmall转为大写赋值给totalBig
                try:
                    chinese_amount = convert_to_chinese_amount(str(total_small))
                    # 无论totalBig是否为空或不等于totalSmall的大写形式，都更新totalBig
                    if 'totalBig' in invoice:
                        modifications['totalBig'] = [invoice['totalBig'], chinese_amount]
                    else:
                        modifications['totalBig'] = [None, chinese_amount]
                    invoice['totalBig'] = chinese_amount
                except Exception as e:
                    print(f"转换金额为大写时出错: {str(e)}")
            
            # 如果totalPrice总和不等于totalAmount，但等于totalSmall-totalTax，也满足基准
            calculated_total_amount = (total_small - total_tax).quantize(Decimal('0.01'))
            if total_price_sum == calculated_total_amount and not item_verify_result["totalPriceAndTotalAmountVerify"]:
                meetVerifyBaseline = True
    except Exception as e:
        print(f"验证基准条件时出错: {str(e)}")
        pass
    
    return invoice, modifications, meetVerifyBaseline, item_verify_result

def dict_compare(dict1, dict2):
    """
    比较两个字典，返回键值不同的内容
    
    参数:
        dict1: 第一个字典
        dict2: 第二个字典
    
    返回:
        diff_dict: 包含不同键值的字典，格式为 {key: [dict1_value, dict2_value]}
    """
    diff_dict = {}
    
    # 获取所有键的集合
    all_keys = set(dict1.keys()) | set(dict2.keys())
    
    # 遍历所有键
    for key in all_keys:
        # 情况1：键只存在于dict1中
        if key in dict1 and key not in dict2:
            diff_dict[key] = [dict1[key], None]
        # 情况2：键只存在于dict2中
        elif key not in dict1 and key in dict2:
            diff_dict[key] = [None, dict2[key]]
        # 情况3：键存在于两个字典中，但值不同
        elif key in dict1 and key in dict2 and dict1[key] != dict2[key]:
            diff_dict[key] = [dict1[key], dict2[key]]
    
    return diff_dict

def print_dict(dict_data:dict):
    for key, value in dict_data.items():
        print(f"{key}: {value}")

         
def correct_invoice_data(invoice_data_list,add_validation_result=False):
    """
    依据函数validate_and_correct_invoice_dict分析处理发票数据列表，返回修正后的结果;
    注意：如果发票数据错误的无法修复（即无法满足基准），则返回原始数据；
    
    验证并修正发票处理思路：
    [
        1）数据预处理
        首先深度复制输入数据，避免修改原始数据
        获取第一个发票数据和第二个发票数据（为invoice_dict_2和differences_dict[k][1]）
        
        2）字段预处理
        处理model字段：如果一个为空，另一个为汉字，则将汉字值赋值给空值
        处理tradeName字段：
            - 一个包含*，一个不包含，则将包含的赋值给不包含的
            - 如果都包含*，则将字段长度长的赋值给短的
        其他差异字段：将差异字典中的值应用到相应字段
        
        3）数据验证与修正
        对两个发票数据分别调用validate_and_correct_invoice_dict进行详细验证和修正
        包括totalPrice验证、taxAmount验证、unit验证、unitPrice和number验证等
        
        4）数据比较和结果整合
        比较两个修正后的发票数据的差异
        更新处理后的数据结构
        可选地添加验证结果信息
    ]
    
    参数:
        invoice_data_list: 原始发票数据列表，格式为 [invoice_dict, validation_dict, [invoice_dict_2, differences_dict]]
        add_validation_result: 是否在返回结果中添加验证结果信息
    
    返回:
        processed_data: 处理后的发票数据列表，格式与输入相同但内容已修正，可能包含额外的验证结果信息
    """
    # 深度复制输入数据，避免修改原始数据
    import copy
    processed_data = copy.deepcopy(invoice_data_list)
    
    # 获取第一个发票数据和第二个发票数据
    invoice_dict_1 = processed_data[0]
    invoice_dict_2 = processed_data[2][0]
    
    # 获取原始第二个字典的差异部分
    ori_diff_dict = processed_data[2][1] if len(processed_data[2]) > 1 else {}
    
    # 记录哪些字段已经被处理过
    processed_fields = set()
    
    # 处理model字段：如果一个为空，另一个为汉字，则将汉字值赋值给空值
    if 'model' in ori_diff_dict:
        # 获取原始model值
        model1 = invoice_dict_1.get('model', "['']")
        model2 = ori_diff_dict['model'][1] if isinstance(ori_diff_dict['model'], list) and len(ori_diff_dict['model']) > 1 else "['']"
        
        # 检查是否为字符串形式的列表，并转换
        if isinstance(model1, str) and model1.startswith('[') and model1.endswith(']'):
            model1_list = model1.replace("'", "").replace("[", "").replace("]", "").split(', ')
        else:
            model1_list = []
            
        if isinstance(model2, str) and model2.startswith('[') and model2.endswith(']'):
            model2_list = model2.replace("'", "").replace("[", "").replace("]", "").split(', ')
        else:
            model2_list = []
        
        # 检查是否有一个为空，一个包含汉字
        model1_empty = all(not item for item in model1_list)
        model2_empty = all(not item for item in model2_list)
        
        model1_has_chinese = any(any('\u4e00' <= char <= '\u9fff' for char in item) for item in model1_list if item)
        model2_has_chinese = any(any('\u4e00' <= char <= '\u9fff' for char in item) for item in model2_list if item)
        
        # 应用规则：一个为空，另一个为汉字，则将汉字值赋值给空值
        if model1_empty and model2_has_chinese:
            invoice_dict_1['model'] = model2
            invoice_dict_2['model'] = model2
        elif model2_empty and model1_has_chinese:
            invoice_dict_1['model'] = model1
            invoice_dict_2['model'] = model1
            
        processed_fields.add('model')
    
    # 处理tradeName字段：一个包含*，一个不包含，则将包含的赋值给不包含的；如果都包含*，则将字段长度长的赋值给短的
    if 'tradeName' in ori_diff_dict:
        # 获取原始tradeName值
        tradeName1 = invoice_dict_1.get('tradeName', "['']")
        tradeName2 = ori_diff_dict['tradeName'][1] if isinstance(ori_diff_dict['tradeName'], list) and len(ori_diff_dict['tradeName']) > 1 else "['']"
        
        # 检查是否为字符串形式的列表，并转换
        if isinstance(tradeName1, str) and tradeName1.startswith('[') and tradeName1.endswith(']'):
            tradeName1_list = tradeName1.replace("'", "").replace("[", "").replace("]", "").split(', ')
        else:
            tradeName1_list = []
            
        if isinstance(tradeName2, str) and tradeName2.startswith('[') and tradeName2.endswith(']'):
            tradeName2_list = tradeName2.replace("'", "").replace("[", "").replace("]", "").split(', ')
        else:
            tradeName2_list = []
        
        # 检查是否包含*
        tradeName1_has_asterisk = any('*' in item for item in tradeName1_list if item)
        tradeName2_has_asterisk = any('*' in item for item in tradeName2_list if item)
        
        # 应用规则：一个包含*，一个不包含，则将包含的赋值给不包含的
        if tradeName1_has_asterisk and not tradeName2_has_asterisk:
            invoice_dict_1['tradeName'] = tradeName1
            invoice_dict_2['tradeName'] = tradeName1
        elif tradeName2_has_asterisk and not tradeName1_has_asterisk:
            invoice_dict_1['tradeName'] = tradeName2
            invoice_dict_2['tradeName'] = tradeName2
        # 如果都包含*，则将字段长度长的赋值给短的
        elif tradeName1_has_asterisk and tradeName2_has_asterisk:
            # 计算总字符长度
            tradeName1_length = sum(len(item) for item in tradeName1_list if item)
            tradeName2_length = sum(len(item) for item in tradeName2_list if item)
            
            if tradeName1_length > tradeName2_length:
                invoice_dict_1['tradeName'] = tradeName1
                invoice_dict_2['tradeName'] = tradeName1
            elif tradeName2_length > tradeName1_length:
                invoice_dict_1['tradeName'] = tradeName2
                invoice_dict_2['tradeName'] = tradeName2
                
        processed_fields.add('tradeName')
    
    # 将其他差异字段的值赋给invoice_dict_2
    for k, v in ori_diff_dict.items():
        if k not in processed_fields and isinstance(v, list) and len(v) > 1:
            invoice_dict_2[k] = v[1]
    
    # 验证并修正两个发票数据
    corrected_invoice1, modifications1, meetVerifyBaseline1, item_verify_result1 = validate_and_correct_invoice_dict(invoice_dict_1)
    corrected_invoice2, modifications2, meetVerifyBaseline2, item_verify_result2 = validate_and_correct_invoice_dict(invoice_dict_2)
    
    # 比较两个修正后的发票数据的差异
    diff_dict = dict_compare(corrected_invoice1, corrected_invoice2)
    
    # 更新处理后的数据
    processed_data[0] = corrected_invoice1
    processed_data[2][0] = corrected_invoice2
    
    # 如果differences_dict不存在，创建它
    if len(processed_data[2]) < 2:
        processed_data[2].append(diff_dict)
    else:
        processed_data[2][1] = diff_dict
    if add_validation_result:
        # 添加验证结果
        processed_data.append({
            "invoice1_validation": {
                "modifications": modifications1,
                "meetVerifyBaseline": meetVerifyBaseline1,
                "item_verify_result": item_verify_result1
            },
            "invoice2_validation": {
                "modifications": modifications2,
                "meetVerifyBaseline": meetVerifyBaseline2,
                "item_verify_result": item_verify_result2
            }
        })
    
    return processed_data

